/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.benchmark.security;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Random;
import java.util.TimeZone;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import cgl.narada.discovery.topics.Entity;
import cgl.narada.discovery.topics.TopicDiscoveryClient;
import cgl.narada.discovery.topics.Topics;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.NBEvent;
import cgl.narada.event.TemplateInfo;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.event.impl.TemplateInfoImpl;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.ClientService;
import cgl.narada.service.client.EventProducer;
import cgl.narada.service.client.SessionService;
import cgl.narada.service.qos.ProducerConstraints;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.TopicRights;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;
import cgl.narada.service.timer.ClockI;
import cgl.narada.service.timer.HRClock;

public class KMCPerfTester {
    static Logger log = Logger.getLogger("KMCPerfTester");

    static {
        PropertyConfigurator
                .configure("/home/hgadgil/research/hpsearch/conf/log4j.properties");
        // Logger.getRootLogger().setLevel(Level.WARN);
    }

    String algo = "AES";
    int keylen = 128;

    public static void main(String[] a) {
        KMCPerfTester sender = new KMCPerfTester(a);
    }

    public KMCPerfTester(String[] a) {
        if (a.length > 1) {
            keylen = Integer.parseInt(a[0]);
        }

        perfTestRegisterSecureTopic(
                "/home/hgadgil/tmp/narada/keystore/NBSecurityTest.keys", 120);
        perfTestRequestSecureTopic(
                "/home/hgadgil/tmp/narada/keystore/NBSecurityTest.keys", 120);
    }

    private String host = "localhost";
    private String port = "25000";
    private String prot = "niotcp";
    private String configFileLocation = "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt";
    private String topicName = "encrypted";
    private String topicUUID;
    private byte[] message = "Hello World !".getBytes();
    private PrivateKey c1_priv;

    private EventProducer producer;

    SecureTopicKeyResponse resp;
    ProducerConstraints pc;

    public void sendMessage() {
        try {
            NBEvent nbEvent = producer.generateEvent(
                    TemplateProfileAndSynopsisTypes.STRING, topicUUID, message);
            producer.publishEvent(nbEvent, pc);
        } catch (ServiceException e) {
            log.error("", e);
        }
    }

    private void init() {

        // IMP: Might conflict w/ other ppl's entity IDs Maintain constant
        // for
        // now
        int entityId = (new Random()).nextInt();

        Properties prop = new Properties();

        prop.put("hostname", host);
        prop.put("portnum", port);

        log.info("SecureTopicsManager:- TCP @ " + host + ":" + port
                + " EntityID[" + entityId + "]");

        try {
            ClientService clientService = SessionService.getClientService(
                    entityId, configFileLocation);

            clientService.initializeBrokerCommunications(prop, prot);

            producer = clientService.createEventProducer();
            producer.setSuppressRedistributionToSource(true);
            producer.generateEventIdentifier(true);
            producer.setTemplateId(12345);
            producer.setDisableTimestamp(false);

            TemplateInfo ti = new TemplateInfoImpl(12345,
                    TemplateProfileAndSynopsisTypes.STRING, topicUUID);

            pc = producer.createProducerConstraints(ti);
            pc.setSendSecurely();
            pc.setSecurityToken(resp.getSignedSecurityToken(), resp.getKey(),
                    c1_priv, null);

        } catch (ServiceException e) {
            log.error("", e);
        }
    }

    private void perfTestRegisterSecureTopic(String keystore, int numTimes) {
        CertificateManager certMan = new CertificateManager();
        certMan.init(keystore, null);

        PublicKey rootCA = CertificateUtil.getPublicKey(certMan,
                certMan.ROOT_CA_ALIAS);

        Certificate c1_cert = CertificateUtil.getCertificate(certMan, "c1");
        c1_priv = CertificateUtil.getPrivateKey(certMan, "c1");

        Calendar until = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
        until.add(Calendar.HOUR, 1);

        Entity e = new Entity(
                9999,
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
                "c1", c1_cert, c1_priv, rootCA, "localhost", "25000", "niotcp");

        if (e == null) {
            System.out.println("ERRRORRRR !!!!");
            return;
        }

        createTopic(e, topicName, TemplateProfileAndSynopsisTypes.STRING, until);

        KMCClient client = new KMCClient(c1_cert, c1_priv, rootCA, "/kmc/c1",
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");

        // Get Signed Topic Ad
        SignedTopicAdvertisement sta = e.getSignedTopicAdvertisement(topicName);

        topicUUID = sta.getTopicAd().getTopicSynopsis();

        // Set the access control lists
        Hashtable pubs = new Hashtable();
        pubs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);

        Hashtable subs = new Hashtable();
        subs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);
        subs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until);

        // Ok, now register the topic and get a security token

        // ClockI hrClock = HRClock.getClock();
        // FileOutputStream fout = null;
        // try {
        // fout = new FileOutputStream("/home/hgadgil/perfTester.out");
        // } catch (FileNotFoundException e2) {
        // // TODO Auto-generated catch block
        // e2.printStackTrace();
        // }
        // long start = 0, end = 0;
        for (int i = 0; i < 1; i++) {
            System.out.println("Run: " + i);

            // start = hrClock.getTimeMicroseconds();

            resp = client.registerTopic(pubs, subs, sta, c1_cert, until, algo,
                    keylen, 5000);
            //            
            // end = hrClock.getTimeMicroseconds();
            // try {
            // fout.write(((end - start) + "\n").getBytes());
            // } catch (IOException e1) {
            // // TODO Auto-generated catch block
            // e1.printStackTrace();
            // }
        }
    }

    private void perfTestRequestSecureTopic(String keystore, int numTimes) {
        CertificateManager certMan = new CertificateManager();
        certMan.init(keystore, null);

        PublicKey rootCA = CertificateUtil.getPublicKey(certMan,
                certMan.ROOT_CA_ALIAS);

        Certificate c2_cert = CertificateUtil.getCertificate(certMan, "c2");
        PrivateKey c2_priv = CertificateUtil.getPrivateKey(certMan, "c2");

        // First discover the topic...
        SignedTopicAdvertisement[] stas = discoverTopics(c2_cert, c2_priv,
                topicName, Topics.MATCHING_STRING, 2);

        KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA, "/kmc/c2",
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");

        // KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA,
        // "/kmc/c2",
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt");

        TopicRights reqRights = new TopicRights(TopicRights.SUBSCRIBE_RIGHT);

        // Now try to get the security token...
        ClockI hrClock = HRClock.getClock();
        FileOutputStream fout = null;
        try {
            fout = new FileOutputStream("/home/hgadgil/perfTester.out");
        } catch (FileNotFoundException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        long start = 0, end = 0;

        for (int i = 0; i < numTimes; i++) {
            System.out.println("Run: " + i);

            start = hrClock.getTimeMicroseconds();

            SecureTopicKeyResponse r2 = client2.requestTopicKey(stas[0]
                    .getTopicAd().getTopicSynopsis(), c2_cert, reqRights, 5000);

            end = hrClock.getTimeMicroseconds();
            try {
                fout.write(((end - start) + "\n").getBytes());
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }

    public boolean createTopic(Entity e, String topicName, int topicType,
            Calendar until) {

        if (e.sendTDNDiscoveryRequest(10000)) {
            System.out.println("Found TDN ! Proceeding to create TOPIC !!");

            if (!e.createTopic("SELF", until, "Test Topic", topicType,
                    topicName, null, 5000)) {
                System.err.println("Could not create topic ! Aborting...");
                return false;
            }

            System.out.println("TOPIC Created: UUID -> "
                    + e.getTopicUUID(topicName));
            return true;
        } else {
            System.out
                    .println("NO TDN found within specified timeout period !!");
            return false;
        }
    }

    public SignedTopicAdvertisement[] discoverTopics(Certificate cert,
            PrivateKey priv, String synopsis, int matchType, int maxTopics) {

        TopicDiscoveryClient disco = new TopicDiscoveryClient(
                15000,
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
                cert, priv, "localhost", "25000", "niotcp");

        // TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt",
        // cert, priv, "localhost", "25000", "niotcp");

        SignedTopicAdvertisement[] stas = disco.discover(matchType, synopsis,
                null, maxTopics);

        disco.close();

        return stas;
    }

}
